#include "ClientHandler.h"

pthread_mutex_t mutex;		//互斥量声明
extern int sockfd;		//全局变量声明
int admin_flag = 0;		//用户身份标志位
int flag_login = 0;		//用户登录标志位
int forbid_flag = 0;		//用户禁言标志位
pthread_t tid[2] = {0};		//记录线程号
char user_id[32] = {0};		//用户名
int msgid_recv;			//消息队列ID
int msgid_send;
int msgkey = 1234;		//消息队列键值初始化

/*
 * 功能：主处理函数
 * 形参：sockfd
 * 返回值：无
 */
void Main_Handler()
{
	int choice;
	while(1)
	{
		menu1();
		printf("\n请选择功能:>");
		scanf("%d", &choice);
		switch(choice)
		{
			case 1:
				user_register();	//注册
				break;
			case 2:
				user_login();		//登录
				break;
			case 3:
				main_exit();		//推出
				break;
			default:
				break;
		}
	}
}

/*
功能:程序退出函数
形参:无
返回值:无
*/
void main_exit()
{
	int ret;
	Chat c_send, c_recv;
	c_send.cmd = CMD_EXIT;

	ret = send(sockfd, &c_send, sizeof(Chat), 0);
	if(ret == -1)
	{
		perror("main_exit_send");
	}
	
	ret = recv(sockfd, &c_recv, sizeof(Chat), 0);
	if(ret == -1)
	{
		perror("main_exit_recv");
	}

	if(c_recv.result == RES_EXIT)
	{
		printf("\n退出中...\n");
		close(sockfd);
		exit(1);
	}
	else
	{
		printf("ERROR\n");
		close(sockfd);
		exit(1);	
	}
}

/*
 * 功能:用户注册
 * 形参:无
 * 返回值:无
 */
void user_register()
{
	int ret;
	Chat c_send, c_recv;
	printf("请输入用户名:>");
	scanf("%s", c_send.id);
	printf("请输入密码:>");
	scanf("%s", c_send.password);
	c_send.cmd = CMD_REGISTER;

	ret = send(sockfd, &c_send, sizeof(c_send), 0);
	if(ret == -1)
	{
		perror("user_register_send");
		exit(1);
	}

	ret = recv(sockfd, &c_recv, sizeof(c_recv), 0);
	if(ret == -1)
	{
		perror("user_register_recv");
		exit(1);
	}

	if (c_recv.result == RES_SUCCESS)
	{
		printf("\n注册成功!\n");
	}
	else if (c_recv.result == RES_USEREXIST)
	{
		printf("\n账户已经存在，注册失败......\n");
	}	
}

void user_login()
{
	int ret;
	srand(time(NULL));
	login();
	if(flag_login == 1)
	{
		printf("登陆成功");
		msgkey = rand();		//键值不能重复，否则同一设备冲突，消息队列
		//创建消息队列
		msgid_send = msgget(msgkey, IPC_CREAT | IPC_EXCL); //IPC_EXCL
		if (-1 == msgid_send)
		{
			perror("user_login msgget1");
			exit(1);
		}

		msgid_recv = msgget(msgkey, 0); 
		if (-1 == msgid_recv)
		{
			perror("main_user_login_msgget2");
			exit(1);
		}
		//登录系统线程
		ret = pthread_create(&tid[0], NULL, login_handler, NULL);
		if(ret == -1)
		{
			perror("login_handler");	
		}
		//接收消息线程
		ret = pthread_create(&tid[1], NULL, recv_handler, NULL);
		if(ret == -1)
		{
			perror("recv_handler");
		}
		
		//阻塞进程
		pthread_join(tid[0], NULL);
		pthread_join(tid[1], NULL);
	}
}

void login()
{
	int ret;
	Chat c_send, c_recv;
	
	printf("请输入用户名:>");
	scanf("%s", c_send.id);
	printf("请输入密码:>");
	scanf("%s", c_send.password);
	
	c_send.cmd = CMD_LOGIN;
	ret = send(sockfd, &c_send, sizeof(c_send), 0);
	if(ret == -1)
	{
		perror("login_send");
	}
	
	ret = recv(sockfd, &c_recv, sizeof(c_send), 0);
	if(ret == -1)
	{
		perror("login_recv");	
	}
	
	if (RES_USERNOTEXIST == c_recv.result)
	{
		printf("\n用户不存在！\n");
		flag_login = 0;
		return;
	}
	else if (RES_PASSWDERROR == c_recv.result)
	{
		printf("\n密码错误！\n");
		flag_login = 0;
		return;
	}
	else if (RES_USERONLINE == c_recv.result)
	{
		printf("\n用户已登录！\n");
		flag_login = 0;
		return;
	}
	else if (RES_SUCCESS == c_recv.result)
	{
		printf("\n登录成功！\n");
		strcpy(user_id, c_send.id);
		flag_login = 1;
		admin_flag = c_recv.admin_flag;
		return;
	}
}

/*
 * 功能：登录系统线程id[0],回调函数
 * 形参：NULL
 * 返回值：无
 */
void *login_handler(void* arg)
{
	int A;
	char id_to[Size_Online][32];	
	
	memset(&id_to, 0, sizeof(id_to));
	
	unsigned int length_online = 0;	//在线人数
	
	while(1)
	{
		menu2();
		printf("\n请输入你选择的功能:>");
		scanf("%d", &A);
		switch(A)
		{
			case 1:
				//查看在线用户信息
				GetOnlineUser(id_to, &length_online);
				ShowOnline(id_to, length_online);
				break;
			case 2:
				//私信
				GetOnlineUser(id_to, &length_online);
				PrivateMsg();
				break;
			case 3:
				//群发
				GetOnlineUser(id_to, &length_online);
				GroupMsg(id_to, length_online);
				break;
			case 4:
				//禁言
				GetOnlineUser(id_to, &length_online);
				ForbidUser();	
				break;
			case 5:
				//踢人
				GetOnlineUser(id_to, &length_online);
				KickOutUser();
				break;
			case 6:
				//注册会员
				RegisterVIP();
				break;
			case 7:
				//传送文件
				GetOnlineUser(id_to, &length_online);
				FileTransfer(id_to, length_online);
				break;
			case 8:
				//获取聊天记录
				GetUserMsg();
				break;
			case 9:
				//下线
				UserExit();
				break;
			defalut:
				printf("\n输入有误！\n");
				break;
		}
	}
}

/*
 * 功能：获取在线用户信息
 * 形参：1、id_to[100]首地址存放用户名(传出) 3、数组大小(传出)
 * 返回值：无
 */
void GetOnlineUser(char (*id_to)[32], unsigned int *length)
{
	int i = 0;
	int ret;
	struct msgbuf msg;
	Chat c_send;

	c_send.cmd = CMD_ONLINEUSER;
	
	ret = send(sockfd, &c_send, sizeof(c_send), 0);
	if(ret == -1)
	{
		perror("GetOlineUser send");
		exit(1);
	}
	c_send.result = RES_WAITINGONLINE;

	while(c_send.result == RES_WAITINGONLINE)
	{
		//消息队列获取
		ret = msgrcv(msgid_send, &msg, sizeof(Chat), 1, 0);
		if(ret == -1)
		{
			perror("getonlineuser msgrcv");	
			exit(1);
		}
	
		memcpy(&c_send, &msg.c_msgbuf, sizeof(Chat));
		strcpy(id_to[i], c_send.id_to);
		
		if(c_send.result == RES_SUCCESS)
		{
			printf("获取用户信息成功！\n");
			break;
		}
		
		i++;
		if(i > Size_Online)	//收100个
		{
			printf("\n 已经达到500人！\n");
			sleep(1);
			break;
		}
	
	}
}

/*
 * 功能：显示所有在线用户信息（从数组中）
 * 形参：1、id_to[100]首地址存放用户名 2、数组长度
 * 返回值：无
 */
void ShowOnline(char (*id_to)[32], unsigned int length)
{
	int i = 0;
	while(length > 0)
	{
		printf("\n%s\n", id_to[i]);
		i++;
		length--;
	}
}

/*
*功能：根据用户名私信
*形参：无
返回值：无
*/
void PrivateMsg()
{
	int ret;
	Chat c_send, c_recv;
	struct msgbuf msg;
	if (1 == forbid_flag)
	{
		printf("\n您已被禁言！\n");
		sleep(1);
		return;
	}

	c_send.cmd = CMD_PRIVATE;
	strcpy(c_send.id, user_id);
	printf("\n我的昵称：%s\n", c_send.id);
	printf("\n请输入对方昵称:>");
	scanf("%s", c_send.id_to);
	
	while(1)
	{
		printf("请输入聊天内容:>");
		scanf("%s", c_send.text);
		if (strcmp(c_send.text, "bye") == 0)
		{
			printf("\n 已退出聊天! \n");
			sleep(1);
			break;
		}
		ret = send(sockfd, &c_send, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("privatemsg send");
			exit(1);
		}
		
		ret = msgrcv(msgid_recv, &msg, sizeof(Chat), 1, 0);
		if (-1 == ret)
		{
			perror("privatemsg msgrcv");
			exit(1);
		}
		
		memcpy(&c_recv, &msg.c_msgbuf, sizeof(Chat));

		if (c_recv.result == RES_SUCCESS)
		{
			printf("\n发送成功！ \n");
		}
		else if (c_recv.result == RES_USEROFFLINE)
		{
			printf("\n 用户不在线！\n");
			break;
		}
	}
}

/*
功能:群发
形参: 1、id_to[100]首地址存放用户名 2、数组长度
返回值:无
*/
void GroupMsg(char (*id_to)[32], unsigned int length)
{
	int ret, j, i = 0;
	struct msgbuf msg;
	Chat c_send, c_recv;
	char id_tmp[100][32] = {0};
	
	c_send.cmd = CMD_GROUP;
	if (1 == forbid_flag)
	{
		printf("\n 您已被禁言！\n");
		sleep(1);
		return;
	}
	while(1)
	{
		printf("\n 请输入聊天内容:>");
		scanf("%s",c_send.text);
		while(length > 1)
		{	
			if(strcmp(id_to[i], user_id) == 0)
			{
				//不给自己发消息
				i++;
				continue;
			}
			
			strcpy(c_send.id_to, id_tmp[i]);
			strcpy(c_send.id, user_id);			

			ret = send(sockfd, &c_send, sizeof(Chat), 0);
			if (-1 == ret)
			{
				perror("groupmsg send");
				exit(1);
			}
			
			
			ret = msgrcv(msgid_recv, &msg, sizeof(Chat), 1, 0);
			if (-1 == ret)
			{
				perror("private_msgrcvs");
				exit(1);
			}		
			
			memcpy(&c_recv, &msg.c_msgbuf, sizeof(Chat));
				
			if (c_recv.result == RES_SUCCESS)
			{
				printf("\n %s发送成功！内容:%s \n", id_tmp[i], c_send.text);
				i++;
				length--;
			}
			else if (c_recv.result == RES_USEROFFLINE)
			{
				printf("\n %s:用户不在线！\n", id_tmp[i]);
				i++; 
				length--;
			}
			
			if (length <= 1)
			{
				printf("\n 群发完成！\n");
			}
		}
	}		
		
}

/*
 * 功能：禁言处理函数
 * 形参：无
 * 返回值：无
 */
void ForbidUser()
{
	int ret;
	Chat c_send, c_recv;
	struct msgbuf msg;
	//判断是否为管理员
	if (admin_flag == 0)
	{
		printf("\n权限不足！\n");
		return;
	}

	strcpy(c_send.id, user_id);
	c_send.cmd = CMD_FORBID;
	
	printf("请输入禁言对象:>");
	scanf("%s", c_send.id_to);
	
	ret = send(sockfd, &c_send, sizeof(c_send), 0);
	if (-1 == ret)
	{
		perror("ForbidUser send");
		exit(1);
	}
	
	ret = msgrcv(msgid_recv, &msg, sizeof(c_send), 1, 0);
	if (-1 == ret)
	{
		perror("ForbidUser msgrcv");
		exit(1);
	}
	
	memcpy(&c_recv, &msg.c_msgbuf, sizeof(Chat));
	if (c_recv.result == RES_SUCCESS)
	{
		printf("\n用户:%s已被禁言！\n", c_send.id_to);
		sleep(1);
	}
	else if (c_recv.result == RES_VIPEXIST)
	{
		printf("\n用户:%s为VIP，禁言失败！\n", c_send.id_to);
		sleep(1);
	}
	else if (c_recv.result == RES_USEROFFLINE)
	{
		printf("\n用户:%s不在线，禁言失败！\n", c_send.id_to);
		sleep(1);
	}
	else if (c_recv.result == RES_USERNOTEXIST)
	{
		printf("\n用户:%s不存在，禁言失败！\n", c_send.id_to);
		sleep(1);
	}
}

/*
 * 功能：踢人下线
 * 形参：无
 * 返回值：无	
 */
void KickOutUser()
{
	Chat c_send, c_recv;
	int ret;
	struct msgbuf msg;

	//判断是否为管理员
	if (admin_flag == 0)
	{
		printf("\n 权限不足！\n");
		sleep(1);
		return;
	}
	
	strcpy(c_send.id, user_id);
	c_send.cmd = CMD_KICKOUT;
	printf("\n 请输入踢出对象昵称:>");
	scanf("%s", c_send.id_to);
	
	ret = send(sockfd, &c_send, sizeof(Chat), 0);
	if (-1 == ret)
	{
		perror("KickOutUser_send");
		exit(1);
	}
	ret = msgrcv(msgid_recv, &msg, sizeof(Chat), 1 , 0);
	if (-1 == ret)
	{
		perror("KickOutUser_msgrcvs");
		exit(1);
	}
	
	memcpy(&c_recv, &msg.c_msgbuf, sizeof(Chat));
	if (c_recv.result == RES_SUCCESS)
	{
		printf("\n 用户：%s已被踢出！\n", c_send.id_to);
		sleep(1);
	}
	else if (c_recv.result == RES_VIPEXIST)
	{
		printf("\n 用户：%s为VIP，踢出失败！\n", c_send.id_to);	
		sleep(1);
	}
	else if (c_recv.result == RES_USEROFFLINE)
	{
		printf("\n 用户：%s不在线，踢出失败！\n", c_send.id_to);
		sleep(1);
	}
	else if (c_recv.result == RES_USERNOTEXIST)
	{
		printf("\n 用户：%s不存在，踢出失败！n", c_send.id_to);
		sleep(1);
	}
}

/*
 * 功能：注册会员
 * 形参：无
 * 返回值：无	
 */
void RegisterVIP()
{
	Chat c_send, c_recv;
	int ret;
	struct msgbuf msg;
	
	strcpy(c_send.id, user_id);
	c_send.cmd = CMD_REGISTERVIP;
	printf("\n请输入激活码:>");
	scanf("%s", c_send.text);	
	ret = send(sockfd, &c_send, sizeof(Chat), 0);
	if (-1 == ret)
	{
		perror("registerVIP send");
		exit(1);
	}
		
	ret = msgrcv(msgid_recv, &msg, sizeof(Chat), 1 , 0);
	if (-1 == ret)
	{
		perror("registerVIP msgrcvs");
		exit(1);
	}

	memcpy(&c_recv, &msg.c_msgbuf, sizeof(Chat));
	if (c_recv.result == RES_NOTADMIN)
	{
		printf("\n 激活码无效！\n");
		sleep(1);
	}
	else if (c_recv.result == RES_VIPEXIST)
	{
		printf("\n 您已是会员，无需重新注册！\n");
		sleep(1);
		admin_flag = 1;
	}
	else if (c_recv.result == RES_SUCCESS)
	{
		printf("\n 注册会员成功！\n");
		sleep(1);
		admin_flag = 1;
	}
}

void FileTransfer(char (*id_to)[32], unsigned int length)
{
	Chat c_send, c_recv;
	int ret, i = 0;
	struct msgbuf msg;
	char filename[32] = {0};
	
	strcpy(c_send.id, user_id);
	system("ls -l");
	printf("\n 输入文件名:>");
	scanf("%s", filename);
	while(1)
	{
		printf("\n 输入传输用户昵称:\n");
		scanf("%s", c_send.id_to);	
		if (strcmp(c_send.id_to, id_to[i++]) == 0 || i >= length)
		{
			break;
		}
	}
	
	if (i >= length)
	{
		printf("\n 对方不在线！\n");
		sleep(1);
		return;
	}
	//以只读方式打开该文件 如果文件不存在 ret = -1
	int fd = open(filename, O_RDONLY);
	if (-1 == ret)
	{	
		printf("\n 文件不存在！\n");
		sleep(1);
		return;
	}
	while(1)
	{	
		//每次从文件读取 sizeof(buf) - 1 字节
		ret = read(fd, c_send.text, sizeof(c_send.text) - 1);
		if (-1 == ret)
		{
			perror("FileTransfer read");
			exit(1);
		}
		else if(ret == 0)
		{
			c_send.result = RES_FILEFINSH;
			ret = send(sockfd, &c_send, sizeof(c_send), 0);
			if(-1 == ret)
			{
				perror("FileTransfer send2");
				exit(1);
			}
			printf("\n 文件传输完毕! \n");
			sleep(1);
			break;
		}
		c_send.result = RES_FILE;
		//将读取的字节传输给服务器
		ret = send(sockfd, &c_send, sizeof(c_send), 0);
		if(-1 == ret)
		{
			perror("FileTransfer_send2");
			exit(1);
		}
	}
	close(fd);
}

/*
 * 功能：获取在线用户信息
 * 形参：1、id_to[100]首地址存放用户名(传出) 3、数组大小(传出)
 * 返回值：无
 */
void GetOlineUser(char (*id_to)[32], unsigned int *length)
{
	Chat c;
	struct msgbuf msg;
	int ret;
	
	c.cmd = CMD_ONLINEUSER;
	strcpy(c.id, user_id);

	ret = send(sockfd, &c, sizeof(c), 0);
	if (-1 == ret)
	{
		perror("getonlineuser_send");
		exit(1);
	}

	memset(&c, 0, sizeof(c));
	c.result = RES_WAITINGONLINE;
	int i = 0;
	while(c.result == RES_WAITINGONLINE)
	{
		ret = msgrcv(msgid_recv, &msg, sizeof(Chat), 1 , 0);
		if (-1 == ret)
		{
			perror("getonlineuser_msgrcv");
			exit(1);
		}		

		memcpy(&c, &msg.c_msgbuf, sizeof(Chat));

		strcpy(id_to[i], c.id_to);
		if (c.result == RES_SUCCESS)
		{
			break;
		}
	
		i++;
		if(i > Size_Online)	//收100个
		{
			printf("\n 已经达到500人！\n");
			sleep(1);
			break;
		}
		*length = (unsigned int)i;
	}
}

void GetUserMsg()
{
	Chat c_send, c_recv;
	int ret;
	struct msgbuf msg;

	c_send.cmd = CMD_GETCHATINFO;
	strcpy(c_send.id, user_id);

	ret = send(sockfd, &c_send, sizeof(Chat), 0);
	if (-1 == ret)
	{
		perror("GetUserMsg_send");
		exit(1);
	}

	while (1)
	{
		ret = msgrcv(msgid_recv, &msg, sizeof(Chat), 1 , 0);
		if (-1 == ret)
		{
			perror("KickOutUser_msgrcvs");
			exit(1);
		}		

		memcpy(&c_recv, &msg.c_msgbuf, sizeof(Chat));
		if (c_recv.result == RES_CHATINFO)
		{
			printf("\n %s \n", c_recv.text);
		}

		if (c_recv.result == RES_CHATINFOEND)
		{
			printf("\n 聊天信息接收完毕！\n");
			sleep(4);
			break;
		}
	}
}


/*
 * 功能：用户下线处理函数：返回到登陆界面
 * 形参：无
 * 返回值：无
 */
void UserExit()
{
	Chat c_send;
	int ret;
	struct msgbuf msg;

	c_send.cmd = CMD_OFFLINE;
	c_send.result = RES_ASKEXIT;
	strcpy(c_send.id, user_id);
	ret = send(sockfd, &c_send, sizeof(c_send), 0);
	if (-1 == ret)
	{
		perror("UserExit_send");
		exit(1);
	}
}

/*
 * 功能：接收线程tid[1]回调函数，专门接收消息的线程
 * 形参：NULL
 * 返回值：无
 */
void *recv_handler(void* arg)
{
	int ret;
	Chat c_recv;
	struct msgbuf MsgBuf;
	while(1)
	{
		ret = recv(sockfd, &c_recv, sizeof(c_recv), 0);
		if(ret == -1)
		{
			perror("recv_handler recv");
			msgctl(msgid_recv, IPC_RMID, NULL);	//关闭消息队列
			pthread_cancel(tid[0]);			//关闭登录线程
			pthread_exit(NULL);			//关闭接收线程
			exit(1);
		}

		if (c_recv.result ==  RES_MESSAGE)
		{
			//收到信息，显示
			printf("来自(%s)的消息:%s", c_recv.id, c_recv.text); 
		}
		else if(c_recv.result == RES_FORBIDSUCCESS)
		{
			//禁言
			forbid_flag = 1;
			printf("\n%s\n", c_recv.text);
		}
		else if(c_recv.result == RES_KICKOUT)
		{
			//被踢下线
			flag_login = 0;
			memset(user_id, 0, sizeof(user_id));
			printf("\n%s\n", c_recv.text);

			msgctl(msgid_recv, IPC_RMID, NULL);	//关闭消息队列
			pthread_cancel(tid[0]);			//关闭登录线程
			pthread_exit(NULL);			//关闭接收线程
		}
		else if(c_recv.result == CMD_FILE)
		{
			RecvFile(&c_recv);
		}
		else if(c_recv.result == RES_USEREXIT)
		{
			printf("\n退出登录中... \n");
			flag_login = 0;
			memset(user_id, 0, sizeof(user_id));	//清空用户名称数
			sleep(1);

			msgctl(msgid_recv, IPC_RMID, NULL);	//关闭消息队列
			pthread_cancel(tid[0]);			//关闭登录线程
			pthread_exit(NULL);			//关闭接收线程
		}
		else if(c_recv.result == 0)
		{
			memset(&MsgBuf, 0, sizeof(MsgBuf));
			memset(&c_recv, 0, sizeof(Chat));

			continue;
		}
		else
		{
			memcpy(&MsgBuf.c_msgbuf, &c_recv, sizeof(Chat));
			MsgBuf.mtype = 1;
			ret = msgsnd(msgid_send, &MsgBuf, sizeof(Chat), 0);
			if (-1 == ret)
			{
				perror("recv_handler_msgsend");
				exit(1);
			}
		}
		memset(&MsgBuf, 0, sizeof(MsgBuf));
		memset(&c_recv, 0, sizeof(Chat));
	}
	return NULL;
}

void RecvFile(Chat *c_recv)
{
	Chat s_end;
	int fd_recv, ret;
	static char filename[32];

	if (RES_FILENAME == c_recv->result)
	{
		strcpy(filename, c_recv->text);
		printf("*****filename = %s\n", filename);
	}
	else if (RES_FILE == c_recv->result)
	{
		printf("filename = %s\n", filename);
		fd_recv = open(filename, O_CREAT | O_WRONLY | O_APPEND, 00700);
 		if (-1 == ret)
		{
			printf("FILE CREATE ERROR！\n");
		}
		ret = write(fd_recv, c_recv->text, strlen(c_recv->text));
		if (-1 == ret)
		{
			perror("write");
			exit(1);
		}
		close(fd_recv);
	}
	else if (RES_FILEFINSH == c_recv->result)
	{
		printf("\t\t\t\033[1;31m文件<%s>接收成功！ \033[0m\n", filename);
		sleep(1);
	}
}

